﻿using System;
using System.Collections.Generic;
using System.Linq;

using Game.Common;
using Game.Map;
using Game.Map.Extensions;
using Game.Objects;

namespace Game.Controller
{
    public class BuildingCapturedEventArgs : EventArgs 
    {
        readonly int _count;
        
        public BuildingCapturedEventArgs(int count)
        {
            _count = count;
        }
        
        public int Count
        {
            get { return _count; }
        }
    }
    
    public class MapWrapper
    {
        public event EventHandler<BuildingCapturedEventArgs> BuildingCaptured;
        public event EventHandler AllBuildingsCaptured;
        public event EventHandler AllHumanVehiclesLost;
        public event EventHandler<HasOwnerEventArgs> PlayerChanged;
        
        readonly IGameMap _gameMap;
        bool _allHumanVehiclesLost;
        
        public MapWrapper(IGameMap gameMap)
        {
            _gameMap = gameMap;
            gameMap.GlobalItems.PlayerChanged += OnPlayerChanged;
            
            foreach(IMapField field in gameMap.Fields)
            {
                field.VehicleX().VehicleAssigned += OnVehicleAssigned;
                
                if (field.VehicleX().Vehicle != null)
                {
                    field.VehicleX().Vehicle.PlayerChanged += OnPlayerChanged2;
                }
            }
        }
        
        public IGameMap GameMap
        {
            get { return _gameMap; }
        }
        
        void OnVehicleAssigned(object sender, FieldVehicleEventArgs e)
        {
            CheckHumanVehicles();
            if (e.MapField.VehicleX().Vehicle != null)
            {
                e.MapField.VehicleX().Vehicle.PlayerChanged += OnPlayerChanged;
                e.MapField.VehicleX().Vehicle.PlayerChanged += OnPlayerChanged2;
            }
        }

        void OnPlayerChanged(object sender, HasOwnerEventArgs e) 
        {
            FirePlayerChanged(e);
            CheckHumanVehicles();
        }
        
        void CheckHumanVehicles() 
        {
            var vehicles = GetVehicle();
            int count = CountHuman(vehicles);

            if (_allHumanVehiclesLost == false && count == 0)
            {
                _allHumanVehiclesLost = true;
                if (AllHumanVehiclesLost != null)
                {
                    AllHumanVehiclesLost(this, new EventArgs());
                }
            }
        }
        
        void OnPlayerChanged2(object sender, HasOwnerEventArgs e)
        {
            int count = CountAi();
            
            if (BuildingCaptured != null)
            {
                BuildingCaptured(this, new BuildingCapturedEventArgs(count));
            }
            
            if (count == 0)
            {
                if (AllBuildingsCaptured != null)
                {
                    AllBuildingsCaptured(this, new EventArgs());
                }
            }
        }

        IEnumerable<Vehicle> GetVehicle()
        {
            var vehicles = new List<Vehicle>();
            
            foreach (var field in _gameMap.Fields) 
            {
                if (field.VehicleX().Vehicle != null) 
                {
                    vehicles.Add(field.VehicleX().Vehicle);
                }

                if (field.MovingX().MovingItem != null)
                {
                    vehicles.Add(field.MovingX().MovingItem);
                }
            }
            
            return vehicles;
        }
        
        int CountAi()
        {
            return _gameMap.GlobalItems.Cast<GameBuilding>().Count(
                item => item.BuildingType.Name == "Headquaters" && item.Owner.IsAi);
        }

        int CountHuman(IEnumerable<Vehicle> vehicles)
        {
            var count = 0;
            
            foreach (var vehicle in vehicles) 
            {
                if (vehicle.Owner != null && vehicle.Owner.IsHuman) 
                {
                    count++;
                }
            }
            
            return count;
        }

        void FirePlayerChanged(HasOwnerEventArgs item)
        {
            if (PlayerChanged != null)
            {
                PlayerChanged(this, item);
            }
        }
    }
}
